﻿using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Web;

using EPiServer.Web.Hosting;
using NCMIS.Client;
using System.ServiceModel.Syndication;
using NCMIS.ObjectModel;
using NCMIS.ServiceModel.Syndication;
using NCMIS.ObjectModel.Rest;

namespace EPiServer.Web.Hosting
{
    public class CmisFileStream : Stream
    {
        protected CmisFile cmisFile;

        protected Stream contentStreamDownload = null;
        protected FileStream contentStreamUpload = null;

        // content upload is temporarily stored in a tempfile on disc rather than "in memory"
        protected string tempFileName;

        protected CmisWebRequest cmisRequest;
        protected FileAccess fileAccess;

        public CmisFileStream(CmisFile file, FileAccess access) : base()
        {
            if(FileAccess.ReadWrite == access)
                throw new NotSupportedException("CmisFileStream does not support Read and Write access at the same time");

            fileAccess = access;
            cmisFile = file;
            cmisRequest = cmisFile.Provider.GetCmisWebRequest();
        }
        
        public override void Close()
        {
            base.Close();

            if(null != contentStreamDownload)
            {
                contentStreamDownload.Close();
                contentStreamDownload = null;
            }

            if(null != contentStreamUpload)
            {
                // flush stream
                contentStreamUpload.Flush();

                // reposition filepointer to beginning
                contentStreamUpload.Seek(0, SeekOrigin.Begin);
                
                if(cmisFile.ShouldCreateFile)
                {
                    // create new document at remote CMIS-repository
                    SyndicationItem docEntry = CmisDocument.CreateDocument(cmisRequest, cmisFile.Name, cmisFile.ParentsChildrenURI, contentStreamUpload);

                    // save 
                    cmisFile.SelfURI = CmisSyndicationItem.GetLink(docEntry, CmisLinkRel.Self).Uri;
                    cmisFile.ContentURI = (docEntry.Content as UrlSyndicationContent).Url;
                    cmisFile.SetLength( contentStreamUpload.Length );
                }

                contentStreamUpload.Close();

                File.Delete(tempFileName);
            }
        }

        public override void Flush()
        {
            if(null != contentStreamUpload)
                contentStreamUpload.Flush();
        }

        public override long Length
        {
            get { return cmisFile.Length; }
        }

        public override long Position
        {
            get
            {
                throw new NotSupportedException("Positioning is not supported");
            }
            set
            {
                throw new NotSupportedException("Positioning is not supported");
            }
        }

        public override int Read(byte[] buffer, int offset, int count)
        {
            if(null == contentStreamDownload)
            {
                contentStreamDownload = cmisRequest.GetContentStream(cmisFile.ContentURI);
            }

            return contentStreamDownload.Read(buffer, offset, count);
        }

        public override long Seek(long offset, SeekOrigin origin)
        {
            throw new NotSupportedException("Seek is not supported");
        }

        public override void SetLength(long value)
        {
            throw new NotSupportedException("SetLength is not supported");
        }

        public override void Write(byte[] buffer, int offset, int count)
        {
            if(null == contentStreamUpload)
            {
                tempFileName = Path.GetTempFileName();
                contentStreamUpload = new FileStream(tempFileName, FileMode.OpenOrCreate, FileAccess.ReadWrite);
            }

            if(null != contentStreamUpload)
                contentStreamUpload.Write(buffer, offset, count);
        }

        public override bool CanRead
        {
            get { return (FileAccess.Read == (fileAccess & FileAccess.Read)); }
        }

        public override bool CanSeek
        {
            get { return false; }
        }

        public override bool CanWrite
        {
            get { return (FileAccess.Write == (fileAccess & FileAccess.Write)); }
        }
    }
}
